home *** CD-ROM | disk | FTP | other *** search
/ ETO Development Tools 2 / ETO Development Tools 2.iso / Tools - Objects / MacApp / MacApp CD Release / MacApp 2.0.1 (Many Libraries) / Libraries / UMemory.inc1.p < prev    next >
Encoding:
Text File  |  1990-10-25  |  40.9 KB  |  1,702 lines  |  [TEXT/MPS ]

  1. {$P}
  2. {[a-,body+,h-,o=100,r+,rec+,t=4,u+,#+,j=20/57/1$,n-]}
  3. { UMemory.inc1.p }
  4. { Copyright © 1985-1990 by Apple Computer, Inc.  All rights reserved. }
  5.  
  6. {$IFC NOT qDebugTheDebugger}
  7. {$W+}
  8. {$R-}
  9. {$Init-}
  10. {$OV-}
  11. {$ENDC}
  12.  
  13. VAR
  14.     pDuringGrowZone: BOOLEAN;
  15.  
  16. FUNCTION GrowZoneProc(needed: Size): LONGINT;
  17.     FORWARD;
  18.  
  19. PROCEDURE BuildCodeReserve(allocLim: Size;
  20.                            fromGZ: BOOLEAN);
  21.     FORWARD;
  22.  
  23. FUNCTION HandleIsEligible(h: Handle): BOOLEAN;
  24.     FORWARD;
  25.  
  26. {--------------------------------------------------------------------------------------------------}
  27.  
  28. PROCEDURE ALoadMacAppSeg;
  29.     EXTERNAL;
  30.  
  31. PROCEDURE APostLoadMacAppSeg;
  32.     EXTERNAL;
  33.  { LoadSeg is Patched to call ALoadMacAppSeg, which in turn calls
  34.   LoadMacAppSegment. ALoadMacAppSeg can only be referenced as a
  35.   procedure pointer, because no args are declared }
  36.  
  37. PROCEDURE EachFrameDo(calleeFrame, ppc: LONGINT;
  38.                       PROCEDURE DoToFrame(calleeFrame: LONGINT;
  39.                                           ppc: LONGINT;
  40.                                           callerFrame: LONGINT;
  41.                                           itsFrame: LONGINT));
  42.     EXTERNAL;
  43.  
  44. FUNCTION PreloadSegment(segNum: INTEGER): BOOLEAN;
  45.     EXTERNAL;
  46.  
  47. PROCEDURE CallNotify(h: Handle;
  48.                      routine: ProcPtr);
  49.     INLINE $205F, $4E90;                                { MOVE.L (A7)+,A0; JSR (A0) }
  50.  
  51. {--------------------------------------------------------------------------------------------------}
  52.  
  53.     {
  54.     These "MAFoo" functions are primarily for THINK™ Pascal compatibility (but useful in the larger
  55.     problem of multiple open resource maps in general); when running under the THINK™ environment,
  56.     CODE resources are not found in the same resource file as other application resources, so a
  57.     UseResFile call needs to be made to bring the project resource file into the search path.
  58.     "gCodeRefNum" is set up at initialization time.
  59.     !!! A much more general solution to "the resource problem" appears to be warranted.
  60.     }
  61.  
  62. {--------------------------------------------------------------------------------------------------}
  63. {$S MAMemoryRes}
  64.  
  65. FUNCTION MAGet1Resource(rType: ResType;
  66.                         rID: INTEGER): Handle;
  67.  
  68.     VAR
  69.         oldResFile:         INTEGER;
  70.  
  71.     BEGIN
  72.     oldResFile := MAUseResFile(gCodeRefNum);
  73.     MAGet1Resource := Get1Resource(rType, rID);
  74.     IF MAUseResFile(oldResFile) <> 0 THEN;
  75.     END;
  76.  
  77. {--------------------------------------------------------------------------------------------------}
  78. {$S MAMemoryRes}
  79.  
  80. FUNCTION MAGet1NamedResource(rType: ResType;
  81.                              name: Str255): Handle;
  82.  
  83.     VAR
  84.         oldResFile:         INTEGER;
  85.  
  86.     BEGIN
  87.     oldResFile := MAUseResFile(gCodeRefNum);
  88.     MAGet1NamedResource := Get1NamedResource(rType, name);
  89.     IF MAUseResFile(oldResFile) <> 0 THEN;
  90.     END;
  91.  
  92. {--------------------------------------------------------------------------------------------------}
  93. {$S MAMemoryRes}
  94.  
  95. FUNCTION MAGet1IndResource(rType: ResType;
  96.                            index: INTEGER): Handle;
  97.  
  98.     VAR
  99.         oldResFile:         INTEGER;
  100.  
  101.     BEGIN
  102.     oldResFile := MAUseResFile(gCodeRefNum);
  103.     MAGet1IndResource := Get1IndResource(rType, index);
  104.     IF MAUseResFile(oldResFile) <> 0 THEN;
  105.     END;
  106.  
  107. {--------------------------------------------------------------------------------------------------}
  108. {$S MAMemoryRes}
  109.  
  110. FUNCTION MACount1Resources(rType: ResType): INTEGER;
  111.  
  112.     VAR
  113.         oldResFile:         INTEGER;
  114.  
  115.     BEGIN
  116.     oldResFile := MAUseResFile(gCodeRefNum);
  117.     MACount1Resources := Count1Resources(rType);
  118.     IF MAUseResFile(oldResFile) <> 0 THEN;
  119.     END;
  120.  
  121. {--------------------------------------------------------------------------------------------------}
  122. {$S MAMemoryRes}
  123.  
  124. FUNCTION MAGetResource(rType: ResType;
  125.                        rID: INTEGER): Handle;
  126.  
  127.     VAR
  128.         h:                    Handle;
  129.         oldResFile:         INTEGER;
  130.  
  131.     BEGIN
  132.     oldResFile := MAUseResFile(gCodeRefNum);
  133.     h := GetResource(rType, rID);
  134.     IF MAUseResFile(oldResFile) <> 0 THEN;
  135.  
  136.     IF HomeResFile(h) <> gCodeRefNum THEN
  137.         h := NIL;
  138.  
  139.     MAGetResource := h;
  140.     END;
  141.  
  142. {--------------------------------------------------------------------------------------------------}
  143. {$S MAMemoryRes}
  144.  
  145. FUNCTION MAGetNamedResource(rType: ResType;
  146.                             name: Str255): Handle;
  147.  
  148.     VAR
  149.         h:                    Handle;
  150.         oldResFile:         INTEGER;
  151.  
  152.     BEGIN
  153.     oldResFile := MAUseResFile(gCodeRefNum);
  154.     h := GetNamedResource(rType, name);
  155.     IF MAUseResFile(oldResFile) <> 0 THEN;
  156.  
  157.     IF HomeResFile(h) <> gCodeRefNum THEN
  158.         h := NIL;
  159.  
  160.     MAGetNamedResource := h;
  161.     END;
  162.  
  163. {--------------------------------------------------------------------------------------------------}
  164. {$S MAMemoryRes}
  165.  
  166. FUNCTION MAGetIndResource(rType: ResType;
  167.                           index: INTEGER): Handle;
  168.  
  169.     VAR
  170.         h:                    Handle;
  171.         oldResFile:         INTEGER;
  172.  
  173.     BEGIN
  174.     oldResFile := MAUseResFile(gCodeRefNum);
  175.     h := GetIndResource(rType, index);
  176.     IF MAUseResFile(oldResFile) <> 0 THEN;
  177.  
  178.     IF HomeResFile(h) <> gCodeRefNum THEN
  179.         h := NIL;
  180.  
  181.     MAGetIndResource := h;
  182.     END;
  183.  
  184. {--------------------------------------------------------------------------------------------------}
  185. {$S MAMemoryRes}
  186.  
  187. FUNCTION MACountResources(rType: ResType): INTEGER;
  188.  
  189.     VAR
  190.         oldResFile:         INTEGER;
  191.  
  192.     BEGIN
  193.     oldResFile := MAUseResFile(gCodeRefNum);
  194.     MACountResources := CountResources(rType);
  195.     IF MAUseResFile(oldResFile) <> 0 THEN;
  196.     END;
  197.  
  198. {--------------------------------------------------------------------------------------------------}
  199. {$S MAMemoryRes}
  200.  
  201. FUNCTION GetSegResource(segNum: INTEGER): Handle;
  202.  
  203.     BEGIN
  204.     IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  205.         GetSegResource := MAGet1Resource(kCode, segNum)
  206.     ELSE
  207.         GetSegResource := MAGetResource(kCode, segNum);
  208.     END;
  209.  
  210. {--------------------------------------------------------------------------------------------------}
  211. {$S MAMiniInit}
  212.  
  213. PROCEDURE AddAllRsrc(rType: ResType;
  214.                      toList: HandleListHandle);
  215.  
  216.     VAR
  217.         oldResLoad:         BOOLEAN;
  218.         i:                    INTEGER;
  219.         h:                    Handle;
  220.         theID:                INTEGER;
  221.         theType:            ResType;
  222.         theName:            Str255;
  223.  
  224.     BEGIN
  225.     oldResLoad := GetResLoad;
  226.     SetResLoad(FALSE);
  227.  
  228.     FOR i := 1 TO CountResources(rType) DO
  229.         BEGIN
  230.         h := GetIndResource(rType, i);
  231.         GetResInfo(h, theID, theType, theName);
  232.  
  233.   { If there is a ROM resource for this type and ID, don't put it
  234.    on the list. }
  235.         UseROMMap(FALSE);
  236.         h := GetResource(rType, theID);
  237.         UseROMMap(FALSE);
  238.         IF HomeResFile(h) <> 1 THEN
  239.             AddHandle(h, toList);
  240.  
  241.         END;
  242.  
  243.     SetResLoad(oldResLoad);
  244.     END;
  245.  
  246. {--------------------------------------------------------------------------------------------------}
  247. {$S MAMiniInit}
  248.  
  249. PROCEDURE AddHandle(h: Handle;
  250.                     toList: HandleListHandle);
  251.  
  252.     VAR
  253.         offset:             LONGINT;
  254.  
  255.     BEGIN
  256.     offset := Munger(Handle(toList), 0, NIL, 0, @h, 4);
  257.     FailMemError;
  258.     END;
  259.  
  260. {--------------------------------------------------------------------------------------------------}
  261. {$S MAMiniInit}
  262.  
  263. FUNCTION AddSegSizes(segRsrc: Handle): LONGINT;
  264.  
  265.     VAR
  266.         p:                    SignedBytePtr;
  267.         oldResLoad:         BOOLEAN;
  268.         total:                LONGINT;
  269.         seg:                Handle;
  270.         i:                    INTEGER;
  271.         s:                    Str255;
  272.  
  273.     BEGIN
  274.     LockHandleHigh(segRsrc);
  275.  
  276.     oldResLoad := GetResLoad;
  277.     SetResLoad(FALSE);
  278.  
  279.     p := SignedBytePtr(segRsrc^);
  280.     i := IntegerPtr(p)^;
  281.     p := SignedBytePtr(Ord(p) + 2);
  282.  
  283.     total := 0;
  284.  
  285.     WHILE i > 0 DO
  286.         BEGIN
  287.         BlockMove(Ptr(p), @s, p^ + 1);
  288.  
  289.         p := SignedBytePtr(Ord(p) + p^ + 1);
  290.         i := i - 1;
  291.  
  292.         IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  293.             seg := MAGet1NamedResource(kCode, s)
  294.         ELSE
  295.             seg := MAGetNamedResource(kCode, s);
  296.  
  297.         IF seg <> NIL THEN
  298.             total := total + SizeResource(seg) + 8;
  299.         END;
  300.  
  301.     AddSegSizes := total;
  302.  
  303.     SetResLoad(oldResLoad);
  304.  
  305.     HUnlock(segRsrc);
  306.     END;
  307.  
  308. {--------------------------------------------------------------------------------------------------}
  309. {$S MAMemoryRes}
  310. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  311.  
  312. PROCEDURE BuildAllReserves;
  313.  
  314.     CONST
  315.         initVal             = $F7;
  316.  
  317.     VAR
  318.         oldPerm:            BOOLEAN;
  319.         {$IFC qDebug}
  320.         theSize:            Size;
  321.         {$EndC}
  322.  
  323.     BEGIN
  324.   { set the permanent flag to ensure that the code reserve is
  325.    actually allocated and not given up to the low space reserve }
  326.     oldPerm := pPermAllocation;
  327.     pPermAllocation := TRUE;
  328.  
  329.     { make sure code reserve is OK }
  330.     BuildCodeReserve(kGZMaxAlloc, FALSE);
  331.  
  332.     { reallocate the low space handle, if necessary }
  333.     IF IsHandlePurged(pMemReserve) THEN
  334.         BEGIN
  335.  
  336.         ReallocHandle(pMemReserve, pSzMemReserve);
  337.         {$IFC qDebug}
  338.         theSize := GetHandleSize(pMemReserve);
  339.         {$Push} {$R-}
  340.         IF theSize <> 0 THEN
  341.             BlockSet(pMemReserve^, theSize, initVal);
  342.         {$Pop}
  343.         {$EndC}
  344.         END;
  345.  
  346.     { reset the permanent flag }
  347.     pPermAllocation := oldPerm;
  348.     END;
  349. {$Pop}
  350.  
  351. {--------------------------------------------------------------------------------------------------}
  352. {$S MAMemoryRes}
  353. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  354.  
  355. PROCEDURE BuildCodeReserve(allocLim: Size;
  356.                            fromGZ: BOOLEAN);
  357.  
  358.     CONST
  359.         initVal             = $F7;
  360.  
  361.     VAR
  362.         needed:             Size;
  363.         avail:                Size;
  364.         canPurge:            Handle;
  365.         {$IFC qDebug}
  366.         theSize:            Size;
  367.         {$EndC}
  368.  
  369.     BEGIN
  370.     pOKCodeReserve := TRUE;                             { default value }
  371.  
  372.     {$IFC qDebug}
  373.     pReserveShortfall := 0;
  374.  
  375.     IF NOT pPermAllocation THEN
  376.         ProgramBreak('BuildCodeReserve called with pPermAllocation = FALSE');
  377.     {$ENDC qDebug}
  378.  
  379.     IF NOT pReserveExists THEN
  380.         BEGIN
  381.         pReserveExists := TRUE;                         { default value }
  382.  
  383.         { free the current code reserve }
  384.         IF HandleIsEligible(pCodeReserve) THEN
  385.             EmptyHandle(pCodeReserve);
  386.  
  387.         { compute amt actually needed }
  388.         needed := Min(pSzCodeReserve - TotalTempSize(FALSE, canPurge) - 8, allocLim);
  389.  
  390.         IF needed > 0 THEN
  391.             BEGIN
  392.             { make as much memory available as possible }
  393.             IF HandleIsEligible(pMemReserve) THEN
  394.                 EmptyHandle(pMemReserve);
  395.  
  396.             IF fromGZ THEN                                { Never purge or compact from GrowZone }
  397.                 avail := allocLim
  398.             ELSE
  399.                 BEGIN
  400.                 PurgeMem(needed);
  401.                 avail := CompactMem(needed);
  402.                 END;
  403.  
  404.             IF avail < needed THEN                        { could not get the whole reserve }
  405.                 BEGIN
  406.                 {$IFC qDebug}
  407.                 pReserveShortfall := needed - avail;
  408.                 {$ENDC}
  409.  
  410.                 pOKCodeReserve := FALSE;
  411.                 pReserveExists := FALSE;
  412.  
  413.                 needed := avail;                        { get the most we can }
  414.                 END;
  415.  
  416.             IF (NOT fromGZ) & (IsHandlePurged(pCodeReserve) | HandleIsEligible(pCodeReserve)) THEN
  417.                     ReallocHandle(pCodeReserve, needed);
  418.             {$IFC qDebug}
  419.             theSize := GetHandleSize(pCodeReserve);
  420.             {$Push} {$R-}
  421.             IF theSize <> 0 THEN
  422.                 BlockSet(pCodeReserve^, theSize, initVal);
  423.             {$Pop}
  424.             {$EndC}
  425.             IF NOT IsHandlePurged(pCodeReserve) THEN
  426.                 BEGIN
  427.                 { Large handles are almost as bad as nonrelocatable blocks.
  428.                     Try to get this guy out of the way, just in case.}
  429.                 IF NOT fromGZ THEN
  430.                     MoveHHi(pCodeReserve);
  431.                 END;
  432.             END;
  433.         END;
  434.     END;
  435. {$Pop}
  436.  
  437. {--------------------------------------------------------------------------------------------------}
  438. {$S MAMemoryRes}
  439.  
  440. FUNCTION CheckReserve: BOOLEAN;
  441.  
  442.     BEGIN
  443.     BuildAllReserves;
  444.     CheckReserve := pOKCodeReserve;
  445.     END;
  446.  
  447. {--------------------------------------------------------------------------------------------------}
  448. {$IFC qDebug}
  449. {$S MAMemoryRes}
  450.  
  451. PROCEDURE CheckRsrcUsage;
  452.  
  453.     VAR
  454.         sz:                 LONGINT;
  455.         h:                    Handle;
  456.         s:                    Str255;
  457.  
  458.     BEGIN
  459.     sz := TotalTempSize(TRUE, h);
  460.     IF sz > gMaxLockedRsrc THEN
  461.         BEGIN
  462.         gMaxLockedRsrc := sz;
  463.         IF gRsrcReport THEN
  464.             BEGIN
  465.             NumToString(gMaxLockedRsrc, s);
  466.             s := Concat('  == New maximum resources usage: ', s, ' ==');
  467.             ProgramReport(s, gMemMgtBreak);
  468.             END;
  469.         END;
  470.     END;
  471. {$ENDC qDebug}
  472.  
  473. {--------------------------------------------------------------------------------------------------}
  474. {$IFC qDebug}
  475. {$S MADebug}
  476.  
  477. PROCEDURE DoChangeReserve(alter: BOOLEAN;
  478.                           VAR codeReserve, codeShort, lowSpaceReserve: LONGINT;
  479.                           VAR gotCode, gotLowSpace: BOOLEAN);
  480.  
  481.     VAR
  482.         x:                    LONGINT;
  483.         s:                    Str255;
  484.  
  485.     BEGIN
  486.     IF alter THEN
  487.         BEGIN
  488.         Write('code reserve size = ', pSzCodeReserve: 1, '  ');
  489.         IF pOKCodeReserve THEN
  490.             Writeln(' (OK)')
  491.         ELSE
  492.             Writeln(' (gone)');
  493.  
  494.         Write('low space reserve size = ', pSzMemReserve: 1, '  ');
  495.         IF NOT IsHandlePurged(pMemReserve) THEN
  496.             Writeln(' (OK)')
  497.         ELSE
  498.             Writeln(' (gone)');
  499.  
  500.         Writeln;
  501.  
  502.         Write('New code reserve (-1 = no change): ');
  503.         Readln(x);
  504.         IF x >= 0 THEN
  505.             codeReserve := x
  506.         ELSE
  507.             codeReserve := pSzCodeReserve;
  508.  
  509.         Write('New low space reserve (-1 = no change): ');
  510.         Readln(x);
  511.         IF x >= 0 THEN
  512.             lowSpaceReserve := x
  513.         ELSE
  514.             lowSpaceReserve := pSzMemReserve;
  515.  
  516.         Write('Reset max resource usage (Y or N) [N]? ');
  517.         Readln(s);
  518.         IF s <> '' THEN
  519.             IF (s[1] = 'y') | (s[1] = 'Y') THEN
  520.                 BEGIN
  521.                 gMaxLockedRsrc := 0;
  522.                 END;
  523.  
  524.         Writeln;
  525.  
  526.         SetReserveSize(codeReserve, lowSpaceReserve);
  527.         END
  528.     ELSE
  529.         BuildAllReserves;
  530.  
  531.     codeReserve := pSzCodeReserve;
  532.     codeShort := pReserveShortfall;
  533.     lowSpaceReserve := pSzMemReserve;
  534.     gotCode := pOKCodeReserve;
  535.     gotLowSpace := NOT IsHandlePurged(pMemReserve);
  536.     END;
  537. {$ENDC qDebug}
  538.  
  539. {--------------------------------------------------------------------------------------------------}
  540. {$S MAMiniInit}
  541.  
  542. PROCEDURE DoInitUMemory(VAR sizeTempReserve, sizeLowSpaceReserve: Size);
  543.  
  544.  { Called from InitUMemory so that InitUMemory can be in the main segment
  545.   and this code can be in another (unloadable) segment. }
  546.  
  547.     TYPE
  548.         Mem                 = RECORD                    { format of the mem! resource }
  549.             codeVal, lowSpaceVal, stackVal: LONGINT;
  550.             END;
  551.         MemPtr                = ^Mem;
  552.         MemHandle            = ^MemPtr;
  553.  
  554.     VAR
  555.         i:                    INTEGER;
  556.         oldResLoad:         BOOLEAN;
  557.         seg:                Handle;
  558.         StackTot:            LONGINT;
  559.         h:                    Handle;
  560.         rsrcID:             INTEGER;
  561.         rsrcType:            ResType;
  562.         rsrcName:            Str255;
  563.         lastRsrc:            INTEGER;
  564.         mainSegment, utilitySegment: INTEGER;
  565.  
  566.     BEGIN
  567.     { Initialize memory management globals }
  568.     pPermAllocation := FALSE;
  569.     pMemReserve := NewHandle(0);
  570.     FailNil(pMemReserve);
  571.  
  572.     pSzMemReserve := 0;
  573.     pCodeReserve := NewHandle(0);
  574.     FailNil(pCodeReserve);
  575.  
  576.     pSzCodeReserve := 0;
  577.     gGZPurgeNotify := NIL;
  578.     pOKCodeReserve := TRUE;
  579.     pReserveExists := FALSE;
  580.     {$IFC qDebug}
  581.     gSegReport := FALSE;
  582.     {$EndC}
  583.  
  584.     gUnloadAllSegs := TRUE;
  585.  
  586.     gCodeRefNum := HomeResFile(GetResource(kCode, 1));    { Get homeresfile of "Main".
  587.                                                         It better be there!!}
  588.     pMaxSegNum := 0;
  589.  
  590.     {###########################################}
  591.     { No resource loading }
  592.  
  593.     oldResLoad := GetResLoad;
  594.     SetResLoad(FALSE);
  595.  
  596.     { Figure the highest segment number }
  597.     IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  598.         lastRsrc := MACount1Resources(kCode)
  599.     ELSE
  600.         lastRsrc := MACountResources(kCode);
  601.  
  602.     { some development systems may not have contiguous numbering of CODE segments.
  603.     try to be polite about handling it }
  604.     FOR i := 1 TO lastRsrc DO
  605.         BEGIN
  606.         IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  607.             seg := MAGet1IndResource(kCode, i)
  608.         ELSE
  609.             seg := MAGetIndResource(kCode, i);
  610.         { we only have an index… find the real resource ID and keep track
  611.         of the highest one }
  612.         IF (seg <> NIL) THEN
  613.             BEGIN
  614.             GetResInfo(seg, rsrcID, rsrcType, rsrcName);
  615.             pMaxSegNum := Max(rsrcID, pMaxSegNum);
  616.             END;
  617.         END;
  618.  
  619.  
  620.     SetResLoad(oldResLoad); { in case of failure }
  621.  
  622.     { Allocate the master segment lists.}
  623.     gCodeSegs := HandleListHandle(NewHandle(pMaxSegNum * SizeOf(Handle)));
  624.     FailNil(gCodeSegs);
  625.  
  626.     gIsResidentSeg := BoolListHandle(NewHandle(SizeOf(BOOLEAN) * pMaxSegNum));
  627.     FailNil(gIsResidentSeg);
  628.  
  629.     gIsLoadedSeg := BoolListHandle(NewHandle(SizeOf(BOOLEAN) * pMaxSegNum));
  630.     FailNil(gIsLoadedSeg);
  631.  
  632.     { (NOTE: assumes application doesn't change the CODE segment size at runtime
  633.     (a very safe assumption)). Used in GetSegFromPC. }
  634.     pSegSize := LongListHandle(NewHandle(SizeOf(LONGINT) * pMaxSegNum));
  635.     FailNil(pSegSize);
  636.  
  637.     oldResLoad := GetResLoad; { OK, suppress segment loading again }
  638.     SetResLoad(FALSE);    { !!! Need an MAResLoad that returns old state }
  639.  
  640.     { Initialize segment lists.}
  641.     FOR i := 1 TO pMaxSegNum DO
  642.         gIsResidentSeg^^[i] := FALSE;
  643.  
  644.     { Segments and their sizes and actual loaded state (helps catch preloads) }
  645.     FOR i := 1 TO pMaxSegNum DO
  646.         BEGIN
  647.         seg := GetSegResource(i);
  648.         gCodeSegs^^[i] := seg;
  649.         if seg <> NIL THEN { seg is non-nil if the segment number exists }
  650.             BEGIN
  651.             pSegSize^^[i] := SizeResource(seg);
  652.             gIsLoadedSeg^^[i] := IsHandleLocked(seg);            
  653.             END
  654.         ELSE
  655.             BEGIN
  656.             pSegSize^^[i] := 0;
  657.             gIsLoadedSeg^^[i] := FALSE;            
  658.             END;
  659.         END;
  660.  
  661.     SetResLoad(oldResLoad);
  662.     {###########################################}
  663.  
  664.     mainSegment := GetSegNumber(@InitUMemory);            { Main is always resident }
  665.     gIsResidentSeg^^[mainSegment] := TRUE;
  666.     gIsLoadedSeg^^[mainSegment] := TRUE;
  667.  
  668.     utilitySegment := GetSegNumber(@UnloadAllSegments); { Utilities are always resident }
  669.     gIsResidentSeg^^[utilitySegment] := TRUE;
  670.     gIsLoadedSeg^^[utilitySegment] := TRUE;
  671.  
  672.     { init the gSysMemList }
  673.     gSysMemList := HandleListHandle(NewHandle(0));
  674.     FailNil(gSysMemList);
  675.  
  676.     AddAllRsrc('LDEF', gSysMemList);
  677.     AddAllRsrc('CDEF', gSysMemList);
  678.     AddAllRsrc('MDEF', gSysMemList);
  679.     AddAllRsrc('WDEF', gSysMemList);
  680.     AddAllRsrc('PACK', gSysMemList);
  681.  
  682.     { Compute memory slop needed }
  683.     sizeTempReserve := 0;
  684.     sizeLowSpaceReserve := 0;
  685.     StackTot := 0;
  686.  
  687.     FOR i := 1 TO CountResources('seg!') DO
  688.         BEGIN
  689.         h := GetIndResource('seg!', i);
  690.         sizeTempReserve := sizeTempReserve + AddSegSizes(h);
  691.         ReleaseResource(h);
  692.         END;
  693.  
  694.     FOR i := 1 TO CountResources('mem!') DO
  695.         BEGIN
  696.         h := GetIndResource('mem!', i);
  697.         WITH MemHandle(h)^^ DO
  698.             BEGIN
  699.             sizeTempReserve := sizeTempReserve + codeVal;
  700.             sizeLowSpaceReserve := sizeLowSpaceReserve + lowSpaceVal;
  701.             StackTot := StackTot + stackVal;
  702.             END;
  703.         ReleaseResource(h);
  704.         END;
  705.  
  706.     SetStackSpace(StackTot);
  707.  
  708.     MaxApplZone;
  709.  
  710.     gApp1MemList := NIL;
  711.     gApp2MemList := NIL;
  712.  
  713.     END;
  714.  
  715. {--------------------------------------------------------------------------------------------------}
  716. {$S MAMemoryRes}
  717.  
  718. PROCEDURE FailNoReserve;
  719.  
  720.     BEGIN
  721.     IF NOT CheckReserve THEN
  722.         Failure(memFullErr, 0);
  723.     END;
  724.  
  725. {--------------------------------------------------------------------------------------------------}
  726. {$S MAMemoryRes}
  727.  
  728. PROCEDURE FailSpaceIsLow;
  729.  
  730. {$IFC qDebug}
  731.  
  732.     VAR
  733.         s:                    MAName;
  734.         {$ENDC}
  735.  
  736.     BEGIN
  737.     {$IFC qDebug}
  738.     IF gAskFailure & CanReadLn THEN
  739.         BEGIN
  740.         GetCallersMethodName(s);
  741.         IF ReadYesNo(Concat('FailSpaceIsLow called by ', s, '.  Return true(Y or N) [N]? ')) THEN
  742.             Failure(memFullErr, 0);
  743.         END;
  744.     {$ENDC}
  745.  
  746.     IF MemSpaceIsLow THEN
  747.         Failure(memFullErr, 0);
  748.     END;
  749.  
  750. {--------------------------------------------------------------------------------------------------}
  751. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  752. {$S MAMemoryRes}
  753.  
  754. PROCEDURE GetReserveSize(VAR szCodeReserve, szMemReserve: Size);
  755.  
  756.     BEGIN
  757.     szCodeReserve := pSzCodeReserve;
  758.     szMemReserve := pSzMemReserve;
  759.     END;
  760. {$Pop}
  761.  
  762. {--------------------------------------------------------------------------------------------------}
  763. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  764.                                                          cannot call to any other segment from this
  765.                                                          procedure }
  766. {$S MAMemoryRes}                                        { Shouldn't be unloaded }
  767.  
  768. FUNCTION GetSegFromPC(ppc: LONGINT): INTEGER;
  769.  
  770.     VAR
  771.         pc:                 LONGINT;
  772.         i:                    INTEGER;
  773.         seg:                Handle;
  774.         segStart:            LONGINT;
  775.  
  776.     BEGIN
  777.     pc := LongintPtr(ppc)^;
  778.  
  779.     GetSegFromPC := 0;                                    { default return }
  780.  
  781.     { Since GetSegFromPC may be called before gCodeSegs is set up, we have to test if gCodeSegs = NIL
  782.     before using it. }
  783.     IF (gCodeSegs <> NIL) THEN
  784.         FOR i := 1 TO pMaxSegNum DO
  785.             BEGIN
  786.             seg := gCodeSegs^^[i];                        { get segment handle }
  787.             IF (seg <> NIL) & NOT IsHandlePurged(seg) THEN { it's in memory }
  788.                 BEGIN
  789.                 segStart := StripLong(seg^);            { get segment start }
  790.                 IF (pc >= segStart) & (pc < segStart + pSegSize^^[i]) THEN
  791.                     BEGIN
  792.                     GetSegFromPC := i;
  793.                     LEAVE;
  794.                     END;
  795.                 END;
  796.             END;
  797.     END;
  798. {$Pop}
  799.  
  800. {--------------------------------------------------------------------------------------------------}
  801. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  802.                                                          cannot call to any other segment from this
  803.                                                          procedure }
  804. {$S MAMemoryRes}                                        { must be in Main segment because we call
  805.                                                          this in order to make the resident segment
  806.                                                          resident }
  807.  
  808. FUNCTION GetSegNumber(aProc: ProcPtr): INTEGER;
  809. { Gets seg number from a Jump table address }
  810.  
  811.     CONST
  812.         kLoaded             = $4EF9;                    { if loaded then a JMP instruction }
  813.         kUnLoaded            = $3F3C;                    { if unloaded then a LoadSeg trap }
  814.  
  815.     VAR
  816.         i:                    INTEGER;
  817.         jt:                 LONGINT;
  818.         segNum:             INTEGER;
  819.         seg:                Handle;
  820.         segStart:            LONGINT;
  821.  
  822.     BEGIN
  823.     IF IntegerPtr(aProc)^ = kLoaded THEN                { loaded segment }
  824.         GetSegNumber := IntegerPtr(Ord(aProc) - 2)^
  825.     ELSE IF IntegerPtr(aProc)^ = kUnLoaded THEN         { unloaded segment }
  826.         GetSegNumber := IntegerPtr(Ord(aProc) + 2)^
  827.     ELSE                                                { routine that computed @proc was in same
  828.                                                          segment as the proc }
  829.         BEGIN
  830.         {$IFC qDebug}
  831.         ProgramBreak('GetSegNumber was not passed an jump table address');
  832.         {$ENDC}
  833.         GetSegNumber := 0;
  834.         END;
  835.     END;
  836. {$Pop}
  837.  
  838. {--------------------------------------------------------------------------------------------------}
  839. {$S MAMemoryRes}
  840. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  841.  
  842. FUNCTION GetSegSize(segNum: INTEGER): Size;
  843.  
  844.     VAR
  845.         curResLoad:         BOOLEAN;
  846.         seg:                Handle;
  847.  
  848.     BEGIN
  849.     GetSegSize := pSegSize^^[segNum];
  850.     END;
  851. {$Pop}
  852.  
  853. {--------------------------------------------------------------------------------------------------}
  854. {$S MAMemoryRes}
  855. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  856.  
  857. FUNCTION GrowZoneProc(needed: Size): LONGINT;
  858.  
  859.     VAR
  860.         result:             LONGINT;
  861.         canPurge:            Handle;
  862.         codeSize:            Size;
  863.         reserveSize:        LONGINT;
  864.         OldA5:                LONGINT;
  865.  
  866.     BEGIN
  867.     OldA5 := SetCurrentA5;                                { Can be called from other worlds }
  868.  
  869.     result := 0;                                        { default is to fail }
  870.     
  871.     IF NOT pDuringGrowZone THEN                            { prevent re-entrancy }
  872.         BEGIN
  873.         pDuringGrowZone := TRUE;
  874.     
  875.         { on a temp alloc, free all code slack immediately }
  876.         IF NOT pPermAllocation & HandleIsEligible(pCodeReserve) THEN
  877.             BEGIN
  878.             EmptyHandle(pCodeReserve);
  879.             pReserveExists := FALSE;
  880.             result := 1;
  881.             END;
  882.     
  883.         IF result = 0 THEN                                    { try harder: see if we can purge a code
  884.                                                              segment or reduce the code reserve handle
  885.                                                              }
  886.             BEGIN
  887.             { compute size of resources currently in memory }
  888.     
  889.             codeSize := TotalTempSize(FALSE, canPurge);
  890.     
  891.             { see if the code reserve handle is too large }
  892.     
  893.             IF HandleIsEligible(pCodeReserve) THEN
  894.                 { we have a code reserve handle; this implies permanent allocation,
  895.                 otherwise the handle would have been emptied above }
  896.                 BEGIN
  897.                 reserveSize := GetHandleSize(pCodeReserve);
  898.     
  899.                 { the following test is an optimization to avoid calling
  900.                 BuildCodeReserve if there is no hope of reducing
  901.                 the code reserve handle }
  902.                 IF codeSize + reserveSize + 8 > pSzCodeReserve THEN
  903.                     BEGIN                                    { reserve is too big }
  904.                     pReserveExists := FALSE;
  905.                     { this should lower the code reserve }
  906.                     BuildCodeReserve(reserveSize, TRUE);
  907.     
  908.                     { see if we succeeded in freeing some memory }
  909.                     IF IsHandlePurged(pCodeReserve) THEN
  910.                         result := 1
  911.                     ELSE IF GetHandleSize(pCodeReserve) < reserveSize THEN
  912.                         result := 1;
  913.                     END;
  914.                 END;
  915.     
  916.             IF (result = 0) & (canPurge <> NIL) & (NOT pPermAllocation |
  917.                IsHandlePurged(pCodeReserve)) THEN           { got something; only purge it if this is
  918.                                                              temporary OR we know there is too much
  919.                                                              code in memory already }
  920.                 BEGIN
  921.                 IF gGZPurgeNotify <> NIL THEN
  922.                     CallNotify(canPurge, gGZPurgeNotify);
  923.     
  924.                 reserveSize := GetHandleSize(canPurge);
  925.                 HPurge(canPurge);
  926.                 EmptyHandle(canPurge);
  927.                 pReserveExists := FALSE;
  928.     
  929.                 IF pPermAllocation THEN                     { don't free too much however }
  930.                     BuildCodeReserve(reserveSize, TRUE);
  931.     
  932.                 result := 1;
  933.                 END;
  934.             END;
  935.     
  936.         IF (result = 0) & HandleIsEligible(pMemReserve) THEN { last ditch attempt-free emergency
  937.                                                               reserve}
  938.             BEGIN
  939.             EmptyHandle(pMemReserve);
  940.             result := 1;
  941.             END;
  942.  
  943.         pDuringGrowZone := FALSE;
  944.         END;
  945.  
  946.     GrowZoneProc := result;
  947.  
  948.     OldA5 := SetA5(OldA5);
  949.     END;
  950. {$Pop}
  951.  
  952. {--------------------------------------------------------------------------------------------------}
  953. {$S MAMemoryRes}
  954. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  955.  
  956. FUNCTION HandleIsEligible(h: Handle): BOOLEAN;
  957.  
  958.     BEGIN
  959.     IF IsHandlePurged(h) THEN
  960.         HandleIsEligible := FALSE
  961.     ELSE
  962.         HandleIsEligible := (h <> GetGZMoveHnd) & (h <> GetGZRootHnd);
  963.     END;
  964. {$Pop}
  965.  
  966. {--------------------------------------------------------------------------------------------------}
  967. {$S MAMemoryRes}                                        { Must be in same segment as grow zone proc
  968.                                                          }
  969. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  970.  
  971. PROCEDURE InstallGrowZoneProc;
  972. { Once called the grow zone proc's segment CANNOT be moved since we're passing a NON-JT address
  973. to SetGrowZone (so we can be called from "other worlds" }
  974.  
  975.     VAR
  976.         aZone:                THz;
  977.  
  978.     BEGIN
  979.     aZone := ApplicZone;
  980.     aZone^.flags := BOR(aZone^.flags, $0400);
  981.   { set the Memory Manager bit that says to always call the
  982.    Grow Zone proc, even in "non-critical" situations }
  983.  
  984.     pDuringGrowZone := FALSE;
  985.  
  986.     SetGrowZone(@GrowZoneProc);
  987.  
  988.     END;
  989. {$Pop}
  990.  
  991. {--------------------------------------------------------------------------------------------------}
  992. {$S Main}                                                { Must be in main segment and called from
  993.                                                          main segment }
  994.  
  995. PROCEDURE InitUMemory;
  996.  
  997.     VAR
  998.         codeRes, lowSpaceRes: Size;
  999.         miniInitSeg, utilitySeg: Handle;
  1000.         mainSeg:    integer;
  1001.  
  1002.     BEGIN
  1003.  
  1004.     { Get these segments out of the way so that when DoInitUMemory gets called and the next
  1005.     block of master pointers gets allocated they won't constipate the heap }
  1006.     miniInitSeg := GetResource(kCode, GetSegNumber(@DoInitUMemory));
  1007.     IF miniInitSeg <> NIL THEN
  1008.         BEGIN
  1009.         UnLoadSeg(@DoInitUMemory);
  1010.         LockHandleHigh(miniInitSeg);
  1011.         END;
  1012.  
  1013.     DoInitUMemory(codeRes, lowSpaceRes);
  1014.  
  1015.     UnloadAllSegments;                                    { get init segment(s) out of middle of heap,
  1016.                                                          so SetReserveSize has maximum space to
  1017.                                                          work with }
  1018.  
  1019.     IF miniInitSeg <> NIL THEN                            { Yes, this would eventually get purged if
  1020.                                                          the space was needed badly enough, but
  1021.                                                          that happens very late in the game and can
  1022.                                                          confound the unwary }
  1023.         EmptyHandle(miniInitSeg);
  1024.  
  1025.     InstallGrowZoneProc;
  1026.  
  1027.     SetReserveSize(codeRes, lowSpaceRes);
  1028.     IF NOT pOKCodeReserve THEN                            { couldn't get code reserve. Can't continue
  1029.                                                          }
  1030.         Failure(memFullErr, 0)
  1031.     ELSE
  1032.     { Set up the LoadSeg patch }
  1033.  
  1034.         FailOSErr(PatchTrap(pSegLoadPatch, _LoadSeg, @ALoadMacAppSeg));
  1035.  
  1036.     END;
  1037.  
  1038. {--------------------------------------------------------------------------------------------------}
  1039. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1040.                                                          cannot call to any other segment from this
  1041.                                                          procedure }
  1042. {$S MAMemoryRes}                                        { must be in Main segment }
  1043.  
  1044. FUNCTION LoadMacAppSegment(segNum: INTEGER): LONGINT;
  1045.  
  1046.     VAR
  1047.         {$IFC qDebug}
  1048.         id:                 INTEGER;
  1049.         kind:                ResType;
  1050.         segName:            Str255;
  1051.         s:                    MAName;
  1052.         seg:                Handle;
  1053.         {$ENDC}
  1054.         A5RegisterOnEntry:    LONGINT;
  1055.  
  1056.     BEGIN
  1057.     A5RegisterOnEntry := SetCurrentA5;                    { ***** Called from trap patches *****}
  1058.  
  1059.     LoadMacAppSegment := pSegLoadPatch.oldTrapAddr;     { Where to go next }
  1060.  
  1061.     IF GetA5 <> A5RegisterOnEntry THEN
  1062.         BEGIN
  1063.         { not called from our application… don't do patch behaviour. Thank you McSink! }
  1064.         pLoadSegCalledFromOwnApp := FALSE;
  1065.         IF SetA5(A5RegisterOnEntry) <> 0 THEN;
  1066.         END
  1067.     ELSE
  1068.         BEGIN
  1069.         pLoadSegCalledFromOwnApp := TRUE;
  1070.         pOldResFile := MAUseResFile(gCodeRefNum);        { Must set a global because we return from
  1071.                                                          this function and then forward to the
  1072.                                                          actual segment loader which should also be
  1073.                                                          pointing to the _now_ correct resfile.
  1074.                                                          When we get called back again in
  1075.                                                          PostLoadMacAppSegment we will restore the
  1076.                                                          old resFile as the current resFile. Sorry
  1077.                                                          about the global. }
  1078.  
  1079.         {$IFC qDebug}
  1080.         IF NOT GetResLoad THEN
  1081.             BEGIN
  1082.             SetResLoad(TRUE);
  1083.             ProgramBreak('Whoops… LoadSeg called with resload set false');
  1084.             Failure(minErr, 0);                         {??? Assign an error code someday or
  1085.                                                          setresload to TRUE ???}
  1086.             END;
  1087.  
  1088.         {$ENDC}
  1089.  
  1090.         IF NOT PreloadSegmentResource(segNum) THEN
  1091.             BEGIN
  1092.             {$IFC qDebug}
  1093.             GetCallersMethodName(s);
  1094.             SetResLoad(FALSE);
  1095.             IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  1096.                 seg := MAGet1Resource(kCode, segNum)
  1097.             ELSE
  1098.                 seg := MAGetResource(kCode, segNum);
  1099.             GetResInfo(seg, id, kind, segName);
  1100.             SetResLoad(TRUE);
  1101.             ProgramBreak(Concat('In ', s, ConcatNumber(' couldn''t load segment: ', segNum), ' ',
  1102.                                 segName));
  1103.             {$ENDC}
  1104.             Failure(memFullErr, 0)
  1105.             END;
  1106.  
  1107.         gIsLoadedSeg^^[segNum] := TRUE;
  1108.  
  1109.         {$IFC qDebug}
  1110.         IF gSegReport THEN
  1111.             BEGIN
  1112.             { Cause the debugger to break at the start of the next routine. }
  1113.             gReportNext := TRUE;
  1114.             GetResInfo(gCodeSegs^^[segNum], id, kind, segName);
  1115.             gReportInfo := Concat(ConcatNumber('  *** Segment Loaded: ', segNum), ' ', segName);
  1116.             gSingleStep := gMemMgtBreak;
  1117.             END;
  1118.         {$ENDC}
  1119.  
  1120.         END;
  1121.     END;
  1122. {$Pop}
  1123.  
  1124. {--------------------------------------------------------------------------------------------------}
  1125. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1126.                                                          cannot call to any other segment from this
  1127.                                                          procedure }
  1128. {$Z+}
  1129. {$S MAMemoryRes}                                        { must be in Main segment }
  1130.  
  1131. PROCEDURE PostLoadMacAppSegment;
  1132.  
  1133.     VAR
  1134.         A5RegisterOnEntry:    LONGINT;
  1135.  
  1136.     BEGIN
  1137.     A5RegisterOnEntry := SetCurrentA5;                    { ***** Called from trap patches *****}
  1138.  
  1139.     IF (GetA5 <> A5RegisterOnEntry) | NOT pLoadSegCalledFromOwnApp THEN
  1140.         BEGIN
  1141.         { not called from our application… don't do patch behaviour. Thank you McSink! }
  1142.         IF SetA5(A5RegisterOnEntry) <> 0 THEN;
  1143.         END
  1144.     ELSE
  1145.     { Called back from our glue.  Restores current res file pointer. }
  1146.         BEGIN
  1147.         IF pLoadSegCalledFromOwnApp THEN
  1148.             IF MAUseResFile(pOldResFile) <> 0 THEN;
  1149.         IF SetA5(A5RegisterOnEntry) <> 0 THEN;
  1150.  
  1151.         END;
  1152.     END;
  1153. {$Pop}
  1154.  
  1155. {--------------------------------------------------------------------------------------------------}
  1156. {$S MAMemoryRes}                                        { Must be in Main segment }
  1157.  
  1158. PROCEDURE LoadResidentSegments;
  1159.  
  1160.     VAR
  1161.         resIndex:            INTEGER;
  1162.         i:                    INTEGER;
  1163.         offset:             INTEGER;
  1164.         nameList:            Handle;
  1165.         segNumber:            INTEGER;
  1166.         p:                    SignedBytePtr;
  1167.         name:                Str255;
  1168.         seg:                Handle;
  1169.         theType:            ResType;
  1170.  
  1171.     BEGIN
  1172.     FOR resIndex := 1 TO CountResources('res!') DO
  1173.         BEGIN
  1174.         nameList := GetIndResource('res!', resIndex);
  1175.         HNoPurge(nameList);
  1176.  
  1177.         offset := 2;
  1178.         FOR i := 1 TO IntegerPtr(nameList^)^ DO
  1179.             BEGIN
  1180.             p := SignedBytePtr(ORD4(nameList^) + offset);
  1181.             BlockMove(Ptr(p), @name, p^ + 1);
  1182.             offset := offset + LENGTH(name) + 1;
  1183.  
  1184.             IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  1185.                 seg := MAGet1NamedResource(kCode, name)
  1186.             ELSE
  1187.                 seg := MAGetNamedResource(kCode, name);
  1188.             IF seg <> NIL THEN
  1189.                 BEGIN
  1190.                 GetResInfo(seg, segNumber, theType, name);
  1191.                 SetResidentSegment(segNumber, TRUE);
  1192.                 END;
  1193.             END;
  1194.  
  1195.         HPurge(nameList);
  1196.         ReleaseResource(nameList);
  1197.         END;
  1198.     END;
  1199.  
  1200. {--------------------------------------------------------------------------------------------------}
  1201. {$S MAMemoryRes}
  1202.  
  1203. FUNCTION MemSpaceIsLow: BOOLEAN;
  1204.  
  1205.     BEGIN
  1206.     BuildAllReserves;
  1207.  
  1208.     MemSpaceIsLow := IsHandlePurged(pMemReserve);
  1209.     END;
  1210.  
  1211. {--------------------------------------------------------------------------------------------------}
  1212. {$S MAMemoryRes}
  1213.  
  1214. FUNCTION NewPermHandle(logicalSize: Size): Handle;
  1215.  
  1216.     CONST
  1217.         initVal             = $F3;                        { odd at all byte boundaries }
  1218.  
  1219.     VAR
  1220.         priorPerm:            BOOLEAN;
  1221.         {$IFC qDebug}
  1222.         aHandle:            Handle;
  1223.         {$EndC}
  1224.  
  1225.     BEGIN
  1226.     priorPerm := PermAllocation(TRUE);
  1227.     {$IFC NOT qDebug}
  1228.     NewPermHandle := NewHandle(logicalSize);
  1229.     {$ELSEC}
  1230.     aHandle := NewHandle(logicalSize);
  1231.     NewPermHandle := aHandle;
  1232.     {$Push} {$R-}
  1233.     IF aHandle <> NIL THEN
  1234.         BlockSet(aHandle^, logicalSize, initVal);
  1235.     {$Pop}
  1236.     {$EndC}
  1237.     pPermAllocation := priorPerm;
  1238.     END;
  1239.  
  1240. {--------------------------------------------------------------------------------------------------}
  1241. {$S MAMemoryRes}
  1242.  
  1243. FUNCTION NewPermPtr(logicalSize: Size): Ptr;
  1244.  
  1245.     CONST
  1246.         initVal             = $F5;                        { odd at all byte boundaries }
  1247.  
  1248.     VAR
  1249.         priorPerm:            BOOLEAN;
  1250.         {$IFC qDebug}
  1251.         aPtr:                Ptr;
  1252.         {$EndC}
  1253.  
  1254.     BEGIN
  1255.     priorPerm := PermAllocation(TRUE);
  1256.     {$IFC NOT qDebug}
  1257.     NewPermPtr := NewPtr(logicalSize);
  1258.     {$ELSEC}
  1259.     aPtr := NewPtr(logicalSize);
  1260.     NewPermPtr := aPtr;
  1261.     {$Push} {$R-}
  1262.     IF aPtr <> NIL THEN
  1263.         BlockSet(aPtr, logicalSize, initVal);
  1264.     {$Pop}
  1265.     {$EndC}
  1266.     pPermAllocation := priorPerm;
  1267.     END;
  1268.  
  1269. {--------------------------------------------------------------------------------------------------}
  1270. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  1271. {$S MAMemoryRes}
  1272.  
  1273. FUNCTION PermAllocation(permanent: BOOLEAN): BOOLEAN;
  1274.  
  1275.     VAR
  1276.         b:                    BOOLEAN;
  1277.  
  1278.     BEGIN
  1279.     PermAllocation := pPermAllocation;
  1280.  
  1281.     IF permanent <> pPermAllocation THEN
  1282.         BEGIN
  1283.         pPermAllocation := permanent;
  1284.  
  1285.         IF permanent THEN
  1286.             BuildCodeReserve(kGZMaxAlloc, FALSE);
  1287.         END;
  1288.     END;
  1289. {$Pop}
  1290.  
  1291. {--------------------------------------------------------------------------------------------------}
  1292. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1293.                                                          cannot call to any other segment from this
  1294.                                                          procedure }
  1295. {$S MAMemoryRes}                                        { must be in Main segment }
  1296.  
  1297. FUNCTION PreloadSegmentResource(segNum: INTEGER): BOOLEAN;
  1298.  
  1299.     VAR
  1300.         seg:                Handle;
  1301.         err:                OSErr;
  1302.  
  1303.     PROCEDURE DoGetSegHandle;
  1304.  
  1305.         BEGIN
  1306.         IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  1307.             seg := Get1Resource(kCode, segNum)
  1308.         ELSE
  1309.             seg := GetResource(kCode, segNum);
  1310.         END;
  1311.  
  1312.     BEGIN
  1313.     IF qDebug & pPermAllocation THEN
  1314.         BEGIN
  1315.         Writeln('segment # = ', segNum: 1);
  1316.         ProgramBreak('Trying to load a segment with PermAllocation = TRUE.');
  1317.         END;
  1318.  
  1319.     WithCodeResFileDo(DoGetSegHandle);
  1320.  
  1321.     IF seg = NIL THEN
  1322.         PreloadSegmentResource := FALSE
  1323.     ELSE
  1324.         BEGIN
  1325.         PreloadSegmentResource := TRUE;
  1326.  
  1327.         IF NOT IsHandleLocked(seg) THEN                 { not yet locked }
  1328.             LockHandleHigh(seg);
  1329.         END;
  1330.     END;
  1331.  
  1332. {--------------------------------------------------------------------------------------------------}
  1333. {$S MAMemoryRes}
  1334.  
  1335. PROCEDURE RemHandle(h: Handle;
  1336.                     toList: HandleListHandle);
  1337.  
  1338.     VAR
  1339.         p:                    LONGINT;
  1340.         maxP:                LONGINT;
  1341.         offset:             LONGINT;
  1342.  
  1343.     BEGIN
  1344.     p := Ord(toList^);                                    { Address of first element }
  1345.     maxP := p + GetHandleSize(Handle(toList));            { Address past last element }
  1346.  
  1347.     { Skip elements until item is found }
  1348.     WHILE (p < maxP) & (LongintPtr(p)^ <> Ord(h)) DO
  1349.         p := p + SizeOf(Handle);
  1350.  
  1351.     IF p < maxP THEN                                    { Item was found }
  1352.         BEGIN
  1353.         offset := Munger(Handle(toList), p - Ord(toList^), NIL, SizeOf(Handle), @h, 0);
  1354.         FailMemError;
  1355.         END;
  1356.     END;
  1357.  
  1358. {--------------------------------------------------------------------------------------------------}
  1359. {$S MAMemoryRes}
  1360. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  1361.  
  1362. PROCEDURE ScanHandles(PROCEDURE DoToHandle(h: Handle));
  1363.  
  1364.     PROCEDURE ScanList(list: HandleListHandle);
  1365.  
  1366.         TYPE
  1367.             HandlePtr            = ^Handle;
  1368.  
  1369.         VAR
  1370.             i:                    INTEGER;
  1371.             p:                    HandlePtr;
  1372.  
  1373.         BEGIN
  1374.         i := GetHandleSize(Handle(list)) DIV SizeOf(Handle);
  1375.  
  1376.         p := HandlePtr(list^);
  1377.         WHILE i > 0 DO
  1378.             BEGIN
  1379.             DoToHandle(p^);
  1380.             p := HandlePtr(Ord(p) + SizeOf(Handle));
  1381.             i := i - 1;
  1382.             END;
  1383.         END;
  1384.  
  1385.     BEGIN
  1386.     ScanList(gCodeSegs);
  1387.     IF gApp1MemList <> NIL THEN
  1388.         ScanList(gApp1MemList);
  1389.     ScanList(gSysMemList);
  1390.     IF gApp2MemList <> NIL THEN
  1391.         ScanList(gApp2MemList);
  1392.     END;
  1393. {$Pop}
  1394.  
  1395. {--------------------------------------------------------------------------------------------------}
  1396. {$S MAMemoryRes}
  1397.  
  1398. PROCEDURE SetPermHandleSize(h: Handle;
  1399.                             newSize: Size);
  1400.  
  1401.     CONST
  1402.         initVal             = $F3;                        { odd at all byte boundaries }
  1403.  
  1404.     VAR
  1405.         priorPerm:            BOOLEAN;
  1406.         {$IFC qDebug}
  1407.         oldSize:            Size;
  1408.         {$EndC}
  1409.  
  1410.     BEGIN
  1411.     priorPerm := PermAllocation(TRUE);
  1412.     {$IFC qDebug}
  1413.     oldSize := GetHandleSize(h);
  1414.     {$EndC}
  1415.     SetHandleSize(h, newSize);
  1416.     pPermAllocation := priorPerm;                        { Since we are in the memory unit we can
  1417.                                                          break the encapsulation of the
  1418.                                                          PermAllocation Call to just set the
  1419.                                                          pPermAllocation flag back directly. This
  1420.                                                          lets us be assured that no operations have
  1421.                                                          occurred that would invalidate the MemErr
  1422.                                                          flag… thus the following call will give a
  1423.                                                          true result}
  1424.     FailMemError;
  1425.     {$IFC qDebug}
  1426.     {$Push} {$R-}
  1427.     IF oldSize < newSize THEN
  1428.         BlockSet(Ptr(Ord(h^) + oldSize), newSize - oldSize, initVal);
  1429.     {$Pop}
  1430.     {$EndC}
  1431.     END;
  1432.  
  1433. {--------------------------------------------------------------------------------------------------}
  1434. {$S MAMemoryRes}
  1435.  
  1436. PROCEDURE SetPermPtrSize(p: Ptr;
  1437.                          newSize: Size);
  1438.  
  1439.     CONST
  1440.         initVal             = $F5;                        { odd at all byte boundaries }
  1441.  
  1442.     VAR
  1443.         priorPerm:            BOOLEAN;
  1444.         {$IFC qDebug}
  1445.         oldSize:            Size;
  1446.         {$EndC}
  1447.  
  1448.     BEGIN
  1449.     priorPerm := PermAllocation(TRUE);
  1450.     {$IFC qDebug}
  1451.     oldSize := GetPtrSize(p);
  1452.     {$EndC}
  1453.     SetPtrSize(p, newSize);
  1454.     pPermAllocation := priorPerm;                        { Since we are in the memory unit we can
  1455.                                                          break the encapsulation of the
  1456.                                                          PermAllocation Call to just set the
  1457.                                                          pPermAllocation flag back directly. This
  1458.                                                          lets us be assured that no operations have
  1459.                                                          occurred that would invalidate the MemErr
  1460.                                                          flag… thus the following call will give a
  1461.                                                          true result}
  1462.     FailMemError;
  1463.     {$IFC qDebug}
  1464.     {$Push} {$R-}
  1465.     IF oldSize < newSize THEN
  1466.         BlockSet(Ptr(Ord(p) + oldSize), newSize - oldSize, initVal);
  1467.     {$Pop}
  1468.     {$EndC}
  1469.     END;
  1470.  
  1471. {--------------------------------------------------------------------------------------------------}
  1472. {$S MAMemoryRes}
  1473.  
  1474. PROCEDURE SetReserveSize(forCode, forOther: Size);
  1475.  
  1476.     VAR
  1477.         oldPerm:            BOOLEAN;
  1478.  
  1479.     BEGIN
  1480.     pSzCodeReserve := forCode;
  1481.     pSzMemReserve := forOther;
  1482.  
  1483.     { Since the numbers have changed, make sure we start from scratch. }
  1484.     pReserveExists := FALSE;
  1485.     EmptyHandle(pMemReserve);
  1486.  
  1487.     BuildAllReserves;
  1488.     END;
  1489.  
  1490. {--------------------------------------------------------------------------------------------------}
  1491. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1492.                                                          cannot call to any other segment from this
  1493.                                                          procedure }
  1494. {$S MAMemoryRes}                                        { must be in Main segment }
  1495.  
  1496. PROCEDURE SetResidentSegment(segNum: INTEGER;
  1497.                              makeResident: BOOLEAN);
  1498.  
  1499.     VAR
  1500.         {$IFC qDebug}
  1501.         id:                 INTEGER;
  1502.         kind:                ResType;
  1503.         segName:            Str255;
  1504.         s:                    MAName;
  1505.         {$ENDC}
  1506.         seg:                Handle;
  1507.  
  1508.     BEGIN
  1509.     IF makeResident THEN
  1510.         BEGIN
  1511.         gIsResidentSeg^^[segNum] := TRUE;
  1512.         IF NOT PreloadSegment(segNum) THEN
  1513.             BEGIN
  1514.             {$IFC qDebug}
  1515.             GetCallersMethodName(s);
  1516.             SetResLoad(FALSE);
  1517.             IF qNeedsROM128k | gConfiguration.hasROM128k THEN
  1518.                 seg := MAGet1Resource(kCode, segNum)
  1519.             ELSE
  1520.                 seg := MAGetResource(kCode, segNum);
  1521.             SetResLoad(TRUE);
  1522.             GetResInfo(seg, id, kind, segName);
  1523.             ProgramBreak(Concat('In ', s, ConcatNumber(' couldn''t load segment: ', segNum),
  1524.                                 ' ', segName));
  1525.             {$ENDC}
  1526.             Failure(memFullErr, 0)
  1527.             END
  1528.         END
  1529.     ELSE
  1530.         BEGIN
  1531.         gIsResidentSeg^^[segNum] := FALSE;
  1532.         END;
  1533.     END;
  1534. {$Pop}
  1535.  
  1536. {--------------------------------------------------------------------------------------------------}
  1537. {$S MAMiniInit}
  1538.  
  1539. PROCEDURE SetStackSpace(numBytes: LONGINT);
  1540.  
  1541.     VAR
  1542.         curLimit:            LONGINT;
  1543.         newLimit:            LONGINT;
  1544.  
  1545.     BEGIN
  1546.     newLimit := Ord(GetCurStackBase) - numBytes;
  1547.  
  1548.     IF Ord(GetApplLimit) > newLimit THEN
  1549.         SetApplLimit(Ptr(newLimit));
  1550.     END;
  1551.  
  1552. {--------------------------------------------------------------------------------------------------}
  1553. {$S MAMemoryRes}
  1554. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  1555.  
  1556. FUNCTION TotalTempSize(justLocked: BOOLEAN;
  1557.                        VAR canPurge: Handle): Size;
  1558.  
  1559.     VAR
  1560.         total:                Size;
  1561.         applZone:            THz;
  1562.  
  1563.     PROCEDURE TotalUp(h: Handle);
  1564.  
  1565.         VAR
  1566.             hIsLocked:            BOOLEAN;
  1567.  
  1568.         BEGIN
  1569.         IF NOT IsHandlePurged(h) THEN                    { in memory already }
  1570.             IF HandleZone(h) = applZone THEN            { in application heap }
  1571.                 BEGIN
  1572.                 HNoPurge(h);
  1573.  
  1574.                 hIsLocked := IsHandleLocked(h);
  1575.  
  1576.                 IF NOT justLocked | hIsLocked THEN
  1577.                     total := total + GetHandleSize(h) + 8;
  1578.                 { add in the size plus heap overhead }
  1579.  
  1580.                 IF NOT hIsLocked THEN
  1581.                     IF canPurge = NIL THEN
  1582.                         IF HandleIsEligible(h) THEN
  1583.                             canPurge := h;
  1584.                 END;
  1585.         END;
  1586.  
  1587.     BEGIN
  1588.     canPurge := NIL;
  1589.     total := 0;
  1590.     applZone := ApplicZone;
  1591.  
  1592.     ScanHandles(TotalUp);
  1593.  
  1594.     TotalTempSize := total;
  1595.     END;
  1596. {$Pop}
  1597.  
  1598. {--------------------------------------------------------------------------------------------------}
  1599. {$S MAMemoryRes}
  1600. {$Push} {$IFC qTrace} {$D+} {$ENDC}
  1601.  
  1602. PROCEDURE WithCodeResFileDo(PROCEDURE DoWithResFile);
  1603.  
  1604.     VAR
  1605.         oldResFile:         INTEGER;
  1606.  
  1607.     BEGIN
  1608.     oldResFile := MAUseResFile(gCodeRefNum);
  1609.     DoWithResFile;
  1610.     IF MAUseResFile(oldResFile) <> 0 THEN;
  1611.     END;
  1612. {$Pop}
  1613.  
  1614. {--------------------------------------------------------------------------------------------------}
  1615. {$Push} {$IFC qTrace} {$D+} {$ENDC}                     { no %_BP/%_EP allowed in here, because we
  1616.                                                          cannot call to any other segment from this
  1617.                                                          procedure }
  1618. {$S MAMemoryRes}                                        { must be in Main segment }
  1619.  
  1620. PROCEDURE UnloadAllSegments;
  1621.  
  1622.     VAR
  1623.         i:                    LONGINT;
  1624.         seg:                Handle;
  1625.         jumpTablePtr:        LONGINT;
  1626.         oldResLoad:         BOOLEAN;
  1627.  
  1628.     PROCEDURE DoToFrame(calleeFrame: LONGINT;
  1629.                         ppc: LONGINT;
  1630.                         callerFrame: LONGINT;
  1631.                         itsFrame: LONGINT);
  1632.  
  1633.         VAR
  1634.             seg:                INTEGER;
  1635.  
  1636.         BEGIN
  1637.         seg := GetSegFromPC(ppc);
  1638.         IF (seg <> 0) & NOT gIsResidentSeg^^[seg] & gIsLoadedSeg^^[seg] THEN
  1639.             BEGIN
  1640.             Writeln('Segment#: ', seg: 2);
  1641.             ProgramBreak(
  1642.        'I really don''t think that you want to unload a segment into which you are going to return!'
  1643.                          )
  1644.             END;
  1645.         END;
  1646.  
  1647.     PROCEDURE UnloadEm;
  1648.  
  1649.         VAR
  1650.             i:                    integer;
  1651.  
  1652.         BEGIN
  1653.         FOR i := 1 TO pMaxSegNum DO
  1654.             IF NOT gIsResidentSeg^^[i] & gIsLoadedSeg^^[i] THEN
  1655.                 BEGIN
  1656.                 seg := gCodeSegs^^[i];
  1657.                 IF (seg <> NIL) & NOT IsHandlePurged(seg) THEN
  1658.                     BEGIN
  1659.                     UnLoadSeg(Ptr(jumpTablePtr + IntegerHandle(seg)^^ + 2));
  1660.                     gIsLoadedSeg^^[i] := FALSE;
  1661.                     END;
  1662.                 END;
  1663.         END;
  1664.  
  1665.     BEGIN
  1666.     {$IFC qDebug}
  1667.     CheckRsrcUsage;
  1668.     {$ENDC}
  1669.  
  1670.     IF gUnloadAllSegs THEN
  1671.         BEGIN
  1672.         jumpTablePtr := Ord(GetA5) + GetCurJTOffset;
  1673.  
  1674.         {$IFC qDebug}
  1675.         EachFrameDo(Ord(GetCurStackFramePtr), Ord(GetCurStackFramePtr) + 4, DoToFrame);
  1676.         {$EndC}
  1677.  
  1678.         WithCodeResFileDo(UnloadEm);
  1679.  
  1680.         {$IFC qDebug}
  1681.         IF gSegReport THEN
  1682.             ProgramReport('  *** Just unloaded all segments ***', gMemMgtBreak);
  1683.         {$ENDC}
  1684.         END;
  1685.     END;
  1686. {$Pop}
  1687.  
  1688. {--------------------------------------------------------------------------------------------------}
  1689. {$IFC qDebug}
  1690. {$S MADebug}
  1691.  
  1692. PROCEDURE WriteReserves;
  1693.  
  1694. { WRITELN's the temporary reserve and low-memory reserves in the
  1695. debug window. }
  1696.  
  1697.     BEGIN
  1698.     WrLblPtr('Temporary reserve (pCodeReserve)', pCodeReserve); Writeln;
  1699.     WrLblPtr('Low-memory reserve (pMemReserve)', pMemReserve); Writeln;
  1700.     END;
  1701. {$ENDC}
  1702.